package com.rainbow.validate.impl

import com.rainbow.emum.ResultEnum
import com.rainbow.validate.*
import org.apache.commons.lang3.StringUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.ServletRequestBindingException
import org.springframework.web.bind.ServletRequestUtils
import org.springframework.web.context.request.ServletWebRequest

/**
 *rainbow
 */
abstract class AbstractValidateCodeProcessor<C : ValidateCode> : ValidateCodeProcessor {


    /**
     * 收集系统中所有的 {@link ValidateCodeGenerator} 接口的实现。
     */
    @Autowired
    private val validateCodeGenerators = mutableMapOf<String, ValidateCodeGenerator>()

    @Autowired
    lateinit var validateCodeRepository: ValidateCodeRepository


    override fun create(request: ServletWebRequest) {
        val validateCode = generate(request)
        save(request, validateCode)
        send(request, validateCode)

    }


    /**
     * 生成验证码
     */
    fun generate(request: ServletWebRequest): C {
        val type = getValidateCodeType(request).toString().toLowerCase()
        val generatorName = type + ValidateCodeGenerator::class.simpleName
        val validateCodeGenerator = validateCodeGenerators.get(generatorName)

        if (validateCodeGenerator == null) {
            throw ValidateCodeException("验证码生成器${validateCodeGenerator}不存在")
        }
        return validateCodeGenerator.generate(request) as C
    }

    /**
     * 根据Holder返回得CodeProcessor类型来获取验证码的类型
     */
    fun getValidateCodeType(request: ServletWebRequest): ValidateCodeType {
        val type = StringUtils.substringBefore(javaClass.simpleName, "CodeProcessor")
        return ValidateCodeType.valueOf(type.toLowerCase())
    }

    /**
     * 保存验证码
     */
    fun save(request: ServletWebRequest, validateCode: C) {
        val code = ValidateCode(validateCode.code!!, validateCode.expireTime!!)
        validateCodeRepository.save(request, code, getValidateCodeType(request))
    }

    /**
     * 发送校验码，由子类实现
     */
    abstract fun send(request: ServletWebRequest, validateCode: C)


    @SuppressWarnings("unchecked")
    override fun validate(request: ServletWebRequest) {
        val codeType = getValidateCodeType(request)

        val codeInSession = validateCodeRepository.get(request, codeType)

        var codeInRequest: String? = null
        try {
            val value = ServletRequestUtils.getStringParameter(request.request, codeType.paramNameOnValidate)
            if (value != null && value.isNotBlank()) {
                codeInRequest = value
            }

        } catch (e: ServletRequestBindingException) {
            throw ValidateCodeException(ResultEnum.CODE_ERROR.code!!, "获取验证码的值失败")
        }

        if (StringUtils.isBlank(codeInRequest) || codeInRequest == null) {
            throw ValidateCodeException(ResultEnum.CODE_ERROR.code!!, "${codeType}验证码的值不能为空")
        }
        if (codeInSession == null) {
            throw ValidateCodeException(ResultEnum.CODE_ERROR.code!!, "${codeType}验证码不存在")
        }
        if (codeInSession.isExpired()) {
            throw ValidateCodeException(ResultEnum.CODE_ERROR.code!!, "${codeType}验证码已过期")
        }
        if (!StringUtils.equals(codeInSession.code, codeInRequest)) {
            throw ValidateCodeException(ResultEnum.CODE_ERROR.code!!, "${codeType}验证码不匹配")
        }

        validateCodeRepository.remove(request, codeType)


    }
}